package com.myk.game.gobangchess.rooms;

import com.myk.game.gobangchess.DataManager;
import com.myk.game.gobangchess.Player;
import com.myk.game.gobangchess.RobotPlayer;
import com.myk.game.gobangchess.Sign;
import com.myk.game.gobangchess.constants.Msger;
import com.myk.game.gobangchess.constants.WinMode;
import com.myk.game.gobangchess.rooms.absrooms.AbsAiRoom;
import com.myk.game.gobangchess.rooms.absrooms.movechess.MoreColorCost;
import com.myk.game.gobangchess.signs.CacheSign;
import com.myk.game.gobangchess.signs.ColorSign;
import com.myk.game.gobangchess.signs.GroundSign;
import com.myk.game.gobangchess.signs.TextSign;
import com.myk.game.gobangchess.utils.GridsUtils;
import com.myk.game.gobangchess.utils.Pair;

import java.util.*;

/**
 * 野牛攻村
 */
public class BisonAiRoom extends AbsAiRoom {

    private CacheSign cacheSign; //棋盘背景缓存标记
    private List<Chess> chessList; //场上棋子集合
    private Chess choose; //选中的目标

    public BisonAiRoom(String roomName) {
        super(roomName, "单人游戏：\n士兵携带猎犬阻止发疯的野牛闯入村庄。\n玩家操控士兵和猎犬，AI操控野牛。", "野牛攻村", GridsUtils.createEmptyGrids(11, 7), false,true);
        initBoardStyle();
        initChessList();
    }

    private void initBoardStyle(){
        List<Sign> boardStyle = new ArrayList<>();
        List<Integer> bGrids = new ArrayList<>();
        List<Integer> wGrids = new ArrayList<>();
        List<Integer> pGrids = new ArrayList<>();
        List<Integer> rGrids = new ArrayList<>();
        for (int i = 0; i < 11; i++) {
            for (int j = 1; j < 6; j++) {
                if ((i + j) % 2 == 0)
                    bGrids.add(getIndex(i, j));
                else
                    wGrids.add(getIndex(i, j));
            }
            if (i % 2 == 0){
                pGrids.add(getIndex(i, 0));
                pGrids.add(getIndex(i, 6));
            }
            else {
                rGrids.add(getIndex(i, 0));
                rGrids.add(getIndex(i, 6));
            }
        }
        boardStyle.add(new ColorSign(bGrids, "#FFC57727"));
        boardStyle.add(new ColorSign(wGrids, "#FF329664"));
        boardStyle.add(new ColorSign(pGrids, "#FFDD6690"));
        boardStyle.add(new ColorSign(rGrids, "#FF9066DD"));
        cacheSign = new CacheSign(this,"background",52,true,boardStyle);
    }

    @Override
    public CacheSign getCacheSignByName(String cacheName) {
        return cacheSign;
    }

    @Override
    public void setBlackPlayer(Player player) {
        if (player instanceof RobotPlayer){
            super.setBlackPlayer(player);
        }
        else {
            player.sendMessage(Msger.broadcast, "野牛棋玩家只能选择白方");
        }
    }

    //delay毫秒后重新开始对局
    public void reStartDelay(long delay) {
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                //点击继续不换位置直接开始
                cur = 1;
                resetGrids();
                noticeAllRefreshRoomInfo();
                DataManager.noticeAllRefreshRoomList();
                checkGameStart();
            }
        }, delay);
    }

    @Override
    public String getRuleText() {
        return "[玩法]\n" +
                "黑(野牛)先行：选择1枚黑子(野牛)向右移动一格，不可越子、不可吃子。\n" +
                "白(玩家)后行，二选一：\n" +
                "——1. 选择1枚白子(猎犬)按国际象棋的“王后”移动，不可越子、不可吃子；\n" +
                "——2. 将红子(士兵)按国际象棋的“国王”移动，不可越子、可以吃敌子；\n" +
                "白方棋子不可进入棋盘最左侧或者最右侧的列。\n\n" +
                "若黑方将任何一枚棋子移至最右列（即野牛成功入侵村落），则黑方获胜；\n" +
                "若轮到黑方时没有合法行动（即玩家成功防御野牛），则白方获胜。";
    }

    @Override
    public String getGameInfo() {
        //先清空棋盘
        curGrids = GridsUtils.copyGrids(originGrids);
        signList.clear();
        //画一下棋盘
        signList.add(cacheSign);
        //画一下棋子
        if (chessList != null){
            for (Chess chess : chessList){
                chess.render();
            }
        }
        //画一下选中效果
        if (choose != null){
            //选中效果
            signList.add(new GroundSign(choose.getIndex(), "#00000000", "#FFFF3838", 1f, 0, 1)) ;
            //画野牛移动范围
            if (choose instanceof Bison){
                for (Integer index : choose.getMoveRange()) {
                    signList.add(new TextSign(index,"🐾","#BB000000"));
                }
            }
            //画士兵或猎犬移动范围
            else {
                List<Integer> range = new ArrayList<>();
                range.addAll(choose.getMoveRange());
                range.addAll(choose.getEatRange());
                for (Integer index : range) {
                    signList.add(new TextSign(index,"👣","#BB000000"));
                }
            }
        }
        return super.getGameInfo();
    }

    @Override
    public void resetGrids() {
        super.resetGrids();
        initChessList();
    }

    private void initChessList() {
        chessList = new ArrayList<>();
        chessList.add(new Bison(this, 0, 0));
        chessList.add(new Bison(this, 1, 0));
        chessList.add(new Bison(this, 2, 0));
        chessList.add(new Bison(this, 3, 0));
        chessList.add(new Bison(this, 4, 0));
        chessList.add(new Bison(this, 5, 0));
        chessList.add(new Bison(this, 6, 0));
        chessList.add(new Bison(this, 7, 0));
        chessList.add(new Bison(this, 8, 0));
        chessList.add(new Bison(this, 9, 0));
        chessList.add(new Bison(this, 10, 0));
        chessList.add(new Hound(this, 4, 5));
        chessList.add(new Hound(this, 6, 5));
        chessList.add(new Soldier(this, 5, 5));
    }

    @Override
    public void doRule(int row, int col, int value) {
        if (choose == null){
            Chess chess = getChessByPos(row, col);
            if (chess !=null && chess.side == value){
                choose = getChessByPos(row, col);
                noticeAllRefreshGameInfo();
            }
        }
        else {
            if (choose.getMoveRange().contains(getIndex(row, col))){
                choose.row = row;
                choose.col = col;
                choose = null;
                stepAdd();
                checkGameOver();
            }
            else if (choose.getEatRange().contains(getIndex(row, col))){
                chessList.remove(getChessByPos(row, col));
                choose.row = row;
                choose.col = col;
                choose = null;
                stepAdd();
                checkGameOver();
            }
            else {
                Chess chess = getChessByPos(row, col);
                if (chess == null || chess.side != value){
                    choose = null;
                    noticeAllRefreshGameInfo();
                }
                else {
                    choose = chess;
                    noticeAllRefreshGameInfo();
                }
            }
        }
    }

    private void checkGameOver() {
        if (isBlackWin()){
            doOver(WinMode.BLACK_WIN, "野牛成功入侵村落！");
        }
        else if (isWhiteWin()){
            doOver(WinMode.WHITE_WIN, "玩家成功消灭野牛！");
        }
        else {
            if (cur == 1){
                noticeWhiteMove();
            }
            else {
                noticeBlackMove();
            }
        }
    }

    private boolean isWhiteWin() {
        for (Chess chess : chessList) {
            if (chess instanceof Bison){
                return false;
            }
        }
        return true;
    }

    private boolean isBlackWin() {
        int maxCol = curGrids[0].length-1;
        for (Chess chess : chessList) {
            if (chess instanceof Bison && chess.col == maxCol){
                return true;
            }
        }
        return false;
    }

    //根据坐标搜索棋子 （有多个棋子时取城门之上的棋子, 可为空）
    public Chess getChessByPos(int row, int col) {
        for (Chess chess : chessList) {
            if (chess.row == row && chess.col == col) {
                return chess;
            }
        }
        return null;
    }

    //根据index搜索棋子 （有多个棋子时取城门之上的棋子, 可为空）
    public Chess getChessByIndex(int index) {
        for (Chess chess : chessList) {
            if (chess.getIndex() == index) {
                return chess;
            }
        }
        return null;
    }

    /**
     * 棋子公共抽象类
     */
    private abstract static class Chess {

        public BisonAiRoom room;
        public String name;
        public int side;
        public int row;
        public int col;

        public Chess(BisonAiRoom room, String name,int side,int row, int col) {
            this.room = room;
            this.name = name;
            this.side = side;
            this.row = row;
            this.col = col;
        }

        //获取棋子的坐标索引
        public int getIndex() {
            return room.getIndex(row, col);
        }

        //获取棋子文字的颜色
        protected String getColor() {
            return side == 1 ? MoreColorCost.BLACK_CHESS_WORD : MoreColorCost.WHITE_CHESS_WORD;
        }

        //根据规则搜索棋子默认的移动范围
        protected List<Integer> defMoveRange(int[][] dxdys, int distance) {
            return defMoveRange(dxdys, distance, 0, 0);
        }

        //根据规则搜索棋子默认的移动范围
        protected List<Integer> defMoveRange(int[][] dxdys, int distance, int canJump, int mustJump) {
            List<Integer> rangeIndex = new ArrayList<>();
            for (int[] dxdy : dxdys) {
                int skip = 0;
                for (int x = row + dxdy[0], y = col + dxdy[1], i = 0; x >= 0 && x < room.curGrids.length && y >= 0 && y < room.curGrids[0].length && i < distance; x += dxdy[0], y += dxdy[1], i++) {
                    if(side==2 && (y==0 || y==6)) break;  //增加了酋长放不能进入最左侧/最右侧列的要求
                    Chess chess = room.getChessByPos(x, y);
                    if (chess != null) { //否则遇到棋子阻碍就得停下
                        skip++;
                        if (skip > canJump) {
                            break;
                        }
                        continue;
                    }
                    if (skip >= mustJump) {
                        rangeIndex.add(room.getIndex(x, y));
                    }
                }
            }
            return rangeIndex;
        }

        //根据规则搜索棋子默认的吃子范围
        protected List<Integer> defEatRange(int[][] dxdys, int distance) {
            return defEatRange(dxdys, distance, 0, 0);
        }

        //根据规则搜索棋子默认的吃子范围
        protected List<Integer> defEatRange(int[][] dxdys, int distance, int canJump, int mustJump) {
            List<Integer> rangeIndex = new ArrayList<>();
            for (int[] dxdy : dxdys) {
                int skip = 0;
                for (int x = row + dxdy[0], y = col + dxdy[1], i = 0; x >= 0 && x < room.curGrids.length && y >= 0 && y < room.curGrids[0].length && i < distance; x += dxdy[0], y += dxdy[1], i++) {
                    if(side==2 && (y==0 || y==6)) break;  //增加了酋长放不能进入最左侧/最右侧列的要求
                    Chess chess = room.getChessByPos(x, y);
                    if (chess != null) {
                        if (chess.side != this.side && skip >= mustJump) {
                            rangeIndex.add(room.getIndex(x, y));
                        }
                        skip++;
                        if (skip > canJump) {
                            break;
                        }
                    }
                }
            }
            return rangeIndex;
        }

        /**
         * 自定义棋子绘制
         */
        public abstract void render();

        /**
         * 自定义 获取可移动空格范围
         */
        public abstract List<Integer> getMoveRange();

        /**
         * 自定义 获取可吃棋子范围
         */
        public abstract List<Integer> getEatRange();

    }

    /**
     * 野牛
     */
    private static class Bison extends Chess {

        public Bison(BisonAiRoom room,int row, int col) {
            super(room,"野牛", 1, row, col);
        }

        @Override
        public void render() {
            //room.curGrids[row][col] = 1;
            room.signList.add(new TextSign(getIndex(), "🐂", getColor()));
        }

        @Override
        public List<Integer> getMoveRange() {
            return defMoveRange(new int[][]{{0, 1}},1);
        }

        @Override
        public List<Integer> getEatRange() {
            return new ArrayList<>();
        }
    }

    /**
     * 猎犬
     */
    private static class Hound extends Chess {
        public Hound(BisonAiRoom room, int row, int col) {
            super(room,"猎犬", 2, row, col);
        }

        @Override
        public void render() {
            //room.curGrids[row][col] = 2;
            room.signList.add(new TextSign(getIndex(), "🐕", getColor()));
        }

        @Override
        public List<Integer> getMoveRange() {
            return defMoveRange(new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {-1, -1}, {-1, 1}, {1, -1}},Integer.MAX_VALUE);
        }

        @Override
        public List<Integer> getEatRange() {
            return new ArrayList<>();
        }
    }

    /**
     * 士兵
     */
    private static class Soldier extends Chess {
        public Soldier(BisonAiRoom room, int row, int col) {
            super(room,"士兵", 2, row, col);
        }

        @Override
        public void render() {
            //room.curGrids[row][col] = 3;
            room.signList.add(new TextSign(getIndex(), "💂", getColor()));
        }

        @Override
        public List<Integer> getMoveRange() {
            return defMoveRange(new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {-1, -1}, {-1, 1}, {1, -1}},1);
        }

        @Override
        public List<Integer> getEatRange() {
            return defEatRange(new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {-1, -1}, {-1, 1}, {1, -1}},1);
        }
    }

    @Override
    protected Player createRobotPlayer() {
        return new RobotPlayer(this, "jk123456ynai", "#野牛", () -> {
            sleep(500);
            Chess target = getAiChooseChess(); //ai任选一个野牛
            //ai选牛移动
            if (target != null){
                choose = target;
                noticeAllRefreshGameInfo();
                sleep(500);
                moveLater(player_black, choose.row, choose.col + 1);
            }
            //ai无法移动
            else {
                doOver(WinMode.WHITE_WIN, "玩家成功阻止野牛！");
            }
        });
    }

    private Chess getAiChooseChess() {
        int maxCol = curGrids[0].length - 1; //棋盘最大列数
        int soldierRow = 0; //士兵所在行
        int dog1Row = -1;
        int dog2Row = -1;
        List<Pair<Chess, Integer>> tempList = new ArrayList<>(); //待选列表
        for (Chess chess : chessList) {
            if (chess instanceof Soldier){
                soldierRow = chess.row;
            }
            if (chess instanceof Hound){
                if (dog1Row == -1) dog1Row = chess.row;
                else dog2Row = chess.row;
            }
            if (chess instanceof Bison && chess.getMoveRange().size()>0) {
                if (chess.col == maxCol-1){
                    return chess; //即将闯入村庄的棋子直接选中
                }
                else {
                    tempList.add(new Pair<>(chess,0));
                }
            }
        }
        if (tempList.size() > 0){
            int scoreALL = 0;
            for (Pair<Chess,Integer> chessPair : tempList) {
                int score1 = chessPair.first.col; //列越靠右越得分，
                int score2 = Math.abs(soldierRow - chessPair.first.row); //离士兵越远越得分
                if (score1 > 0){
                    score1 = (score1 * score1 - score1 + 2)/2; //用累加法数列求和的方式求得的公式 (n*n-n+2)/2，数列为1，2，4，7，11，16......
                }
                if (score2 > 0){
                    score2 = (score2 * score2 - score2 + 2)/2;
                }
                int scoreT = score1 + score2 + 1; //不许有0分的所以＋1
                chessPair.second = scoreT;
                scoreALL += scoreT;
            }
            int randomScore = (int) (Math.random() * scoreALL);
            for (Pair<Chess,Integer> chessPair : tempList) {
                if (randomScore < chessPair.second){
                    return chessPair.first;
                }
                randomScore -= chessPair.second;
            }
        }
        return null;
    }

}
